package sk.vrto.service.dao.hibernate;

import org.hibernate.Query;
import org.hibernate.Session;
import sk.vrto.domain.Contact;
import sk.vrto.domain.ContactCreation;
import sk.vrto.domain.User;
import sk.vrto.service.dao.ContactRepository;
import sk.vrto.service.domain.ContactCreator;
import sk.vrto.web.ApplicationInjector;

import java.util.Collection;
import java.util.List;

/**
 * ContactRepository that uses SQL database to obtain contacts from.
 * Uses Hibernate as an ORM provider.
 */
@SuppressWarnings("unchecked")
public class HibernateContactRepository implements ContactRepository {

    private final ContactCreator contactCreator;

    public HibernateContactRepository(ContactCreator contactCreator) {
        this.contactCreator = contactCreator;
    }

    @Override
    public Collection<Contact> loadContatsForUser(User user) {
        Session session = ApplicationInjector.getSessionFactory().openSession();
        try {
            session.beginTransaction();
            Query query = session.createQuery("from Contact c where c.user = :user");
            query.setParameter("user", user);
            List<Contact> contacts = query.list();
            session.getTransaction().commit();
            return contacts;
        } finally {
            session.close();
        }
    }

    @Override
    public ContactCreation getOrCreate(String emailAddress, User forUser) {
        boolean freshlyCreated = false;
        Contact contact = find(emailAddress);

        if (null == contact) {
            freshlyCreated = true;
            contact = contactCreator.mapFromAddress(emailAddress, forUser);
            insert(contact);
        }

        return new ContactCreation(contact, freshlyCreated);
    }

    @Override
    public Contact find(String key) {
        Session session = ApplicationInjector.getSessionFactory().openSession();
        try {
            session.beginTransaction();
            Query query = session.createQuery("from Contact c where c.email = :email");
            query.setParameter("email", key);
            List<?> result = query.list();
            Contact contact = result.isEmpty() ? null : (Contact) result.get(0);
            session.getTransaction().commit();
            return contact;
        } finally {
            session.close();
        }
    }

    @Override
    public Collection<Contact> load() {
        Session session = ApplicationInjector.getSessionFactory().openSession();
        try {
            session.beginTransaction();
            Query query = session.createQuery("from Contact");
            List<Contact> contacts = query.list();
            session.getTransaction().commit();
            return contacts;
        } finally {
            session.close();
        }
    }

    @Override
    public void insert(Contact contact) {
        Session session = ApplicationInjector.getSessionFactory().openSession();
        try {
            session.beginTransaction();
            session.saveOrUpdate(contact);
            session.getTransaction().commit();
        } finally {
            session.close();
        }
    }

    @Override
    public void update(Contact contact) {
        insert(contact);
    }

    @Override
    public void delete(Contact contact) {
        Session session = ApplicationInjector.getSessionFactory().openSession();
        try {
            session.beginTransaction();
            session.delete(contact);
            session.getTransaction().commit();
        } finally {
            session.close();
        }
    }

}
